'************************************************************************************
' Copyright  2003-2005 Kathleen Dollard
'
' This software is provided 'as-is', without any express or implied warranty. In no 
' event will the author be held liable for any damages arising from the use of this
' software.
' 
' You may use this software for any purpose, including commercial applications, 
' and you may redistribute this software as part of application delivery: however, 
' this copyright notice may not be removed and you may not otherwise redistribute 
' this software directly other than providing a link to wwww.gendotnet.com. 
'
' You may alter this software to better server your needs (I'd like to hear about your 
' changes in order to make the software better). If you alter the softwre, you must  
' clearly mark it as altered and must not be misrepresented as the original software.
' nor wholly your original work.
'*************************************************************************************
'  Summary: Tools to facilitate working with XML. 
'  Note: Additional tools are in the Tools class

Option Strict On
Option Explicit On

Imports System

'! Class Summary: 

Namespace KADGen.Utility
   Public Class xmlHelpers

      Private Class nspaceLookup
         Public nspace As String
         Public prefix As String
      End Class


#Region "Class level declarations"
      Const vbcrlf As String = Microsoft.VisualBasic.ControlChars.CrLf
      Public Const xsiNamespaceURI As String = "http://www.w3.org/2001/XMLSchema-instance"
      Public Const xsdNamespaceURI As String = "http://www.w3.org/2001/XMLSchema"
#End Region

      '#Region "Constructors "
      '#End Region

#Region "Public Methods and Properties"

#Region "BuildNamespace methods"
      ' . THere are too many, need to clean up
      Public Shared Function BuildNamespacesManagerForDoc( _
                  ByVal xmlDoc As Xml.XmlDocument) _
                  As Xml.XmlNamespaceManager
         Dim nsmgrXML As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
         BuildNamespacesManagerForDoc(xmlDoc, nsmgrXML)
         Return nsmgrXML
      End Function
      Public Shared Function BuildNamespacesManagerForDoc( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal defaultNamespacePrefix As String) _
                  As Xml.XmlNamespaceManager
         Dim nsmgrXML As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
         BuildNamespacesManagerForDoc(xmlDoc, defaultNamespacePrefix, nsmgrXML)
         Return nsmgrXML
      End Function
      Public Shared Sub BuildNamespacesManagerForDoc( _
               ByVal xmlDoc As Xml.XmlDocument, _
               ByVal nsmgrXML As Xml.XmlNamespaceManager)
         BuildNamespacesManagerForDoc(xmlDoc, "zzz", nsmgrXML)
      End Sub
      Public Shared Sub BuildNamespacesManagerForDoc( _
               ByVal xmlDoc As Xml.XmlDocument, _
               ByVal defaultNamespacePrefix As String, _
               ByVal nsmgrXML As Xml.XmlNamespaceManager)
         Dim nodes As Xml.XmlNodeList
         Dim nSpace As nspaceLookup
         Dim collection As New Collections.Hashtable
         'Diagnostics.Debug.WriteLine(DateTime.Now)
         nodes = xmlDoc.SelectNodes("//*")
         For Each node As Xml.XmlNode In nodes
            nSpace = New nspaceLookup
            nSpace.nspace = node.NamespaceURI
            nSpace.prefix = node.Prefix
            If Not collection.Contains(nSpace.prefix & ":" & nSpace.nspace) Then
               collection.Add(nSpace.prefix & ":" & nSpace.nspace, nSpace)
            End If
         Next
         'Diagnostics.Debug.WriteLine(DateTime.Now)

         For Each d As Collections.DictionaryEntry In collection
            nSpace = CType(d.Value, nspaceLookup)
            If nSpace.prefix.Trim.Length = 0 Then
               nSpace.prefix = defaultNamespacePrefix
            End If
            nsmgrXML.AddNamespace(nSpace.prefix, nSpace.nspace)
         Next
         ' CHANGED: KAD 20041026 Removed the following line
         'nsmgrXML.AddNamespace("kg", "http://kadgen.com/KADGenDriving.xsd")

         'For Each prefix As String In nsmgrXML
         '   Console.WriteLine("Prefix={0}, Namespace={1}", prefix, nsmgrXML.LookupNamespace(prefix))
         'Next
      End Sub

      Public Shared Function BuildNamespacesManagerForRoot( _
            ByVal xmlDoc As Xml.XmlDocument) _
            As Xml.XmlNamespaceManager
         Dim nsmgrXML As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
         BuildNamespacesManagerForRoot(xmlDoc, nsmgrXML)
         Return nsmgrXML
      End Function
      Public Shared Function BuildNamespacesManagerForRoot( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal defaultNamespacePrefix As String) _
                  As Xml.XmlNamespaceManager
         Dim nsmgrXML As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
         BuildNamespacesManagerForRoot(xmlDoc, defaultNamespacePrefix, nsmgrXML)
         Return nsmgrXML
      End Function
      Public Shared Sub BuildNamespacesManagerForRoot( _
               ByVal xmlDoc As Xml.XmlDocument, _
               ByVal nsmgrXML As Xml.XmlNamespaceManager)
         BuildNamespacesManagerForRoot(xmlDoc, "zzz", nsmgrXML)
      End Sub
      Public Shared Sub BuildNamespacesManagerForRoot( _
               ByVal xmlDoc As Xml.XmlDocument, _
               ByVal defaultNamespacePrefix As String, _
               ByVal nsmgrXML As Xml.XmlNamespaceManager)
         Dim node As Xml.XmlNode
         Dim nSpace As nspaceLookup
         Dim collection As New Collections.Hashtable
         ' Diagnostics.Debug.WriteLine(DateTime.Now)
         node = Utility.xmlHelpers.GetRootNode(xmlDoc)
         nSpace = New nspaceLookup
         nSpace.nspace = node.NamespaceURI
         nSpace.prefix = node.Prefix
         If nSpace.prefix.Trim.Length = 0 Then
            nSpace.prefix = defaultNamespacePrefix
         End If
         nsmgrXML.AddNamespace(nSpace.prefix, nSpace.nspace)
      End Sub

      Public Shared Function GetNamespace( _
                     ByVal xmlDoc As Xml.XmlDocument, _
                     ByVal prefix As String) _
                     As String
         Dim node As Xml.XmlNode = xmlDoc.ChildNodes(1)
         If prefix.Trim.Length = 0 Then
            Return Tools.GetAttributeOrEmpty(node, "xmlns")
         Else
            Return Tools.GetAttributeOrEmpty(node, "xmlns:" & prefix)
         End If
      End Function


      Public Shared Function BuildNameSpaceManager( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal node As Xml.XmlNode, _
                  ByVal elemName As String, _
                  ByVal nsmgr As Xml.XmlNamespaceManager, _
                  ByVal prefix As String) _
                  As Xml.XmlNamespaceManager
         Dim namespaceName As String = Tools.GetAttributeOrEmpty(node, elemName, prefix & "Namespace", nsmgr)
         Dim NSPrefix As String = Tools.GetAttributeOrEmpty(node, elemName, prefix & "NSPrefix", nsmgr)
         Dim newNsmgr As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
         newNsmgr.AddNamespace(NSPrefix, namespaceName)
         Return newNsmgr
      End Function


      Public Shared Function BuildNamespaceManager( _
                  ByVal node As Xml.XmlNode, _
                  ByVal includeXSD As Boolean) _
                  As Xml.XmlNamespaceManager
         Return BuildNamespaceManager(node, "", includeXSD)
      End Function

      Public Shared Function BuildNamespaceManager( _
                  ByVal node As Xml.XmlNode, _
                  ByVal prefix As String, _
                  ByVal includeXSD As Boolean) _
                  As Xml.XmlNamespaceManager
         Dim ownerDocument As Xml.XmlDocument
         If node Is Nothing Then
            Diagnostics.Debug.WriteLine("Node can not be nothing")
         Else
            If TypeOf node Is Xml.XmlDocument Then
               ownerDocument = CType(node, Xml.XmlDocument)
            Else
               ownerDocument = node.OwnerDocument
            End If
            Return BuildNamespaceManager(ownerDocument, prefix, includeXSD)
         End If
         Return Nothing
      End Function

      Public Shared Function BuildNamespaceManager( _
                     ByVal doc As Xml.XmlDocument, _
                     ByVal prefix As String, _
                     ByVal includeXSD As Boolean) _
                     As Xml.XmlNamespaceManager
         If doc Is Nothing Then
            Diagnostics.Debug.WriteLine("Doc should not be nothing")
         Else
            Dim nsmgr As Xml.XmlNamespaceManager = New Xml.XmlNamespaceManager(doc.NameTable)
            nsmgr.AddNamespace(prefix, GetNamespace(doc, prefix))
            If includeXSD Then
               nsmgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema")
            End If
            Return nsmgr
         End If
         Return Nothing
      End Function
#End Region

      Public Shared Sub AddXSDNamespaceToManager(ByVal namespaceManager As Xml.XmlNamespaceManager)
         namespaceManager.AddNamespace("xs", xsdNamespaceURI)
      End Sub

      Public Shared Function GetXSDNamespaceManager() As Xml.XmlNamespaceManager
         Dim namespaceManager As New Xml.XmlNamespaceManager( _
                        New System.Xml.NameTable)
         namespaceManager.AddNamespace("xs", xsdNamespaceURI)
         Return namespaceManager
      End Function

#Region "NewElement"
      Public Shared Function NewElement( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String, _
                  ByVal name As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(elementName)
         nodeElement.Attributes.Append(xmlHelpers.NewAttribute( _
                  xmlDoc, "Name", name))
         Return nodeElement
      End Function

      Public Shared Function NewElement( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(elementName)
         Return nodeElement
      End Function

      Public Shared Function NewElement( _
                  ByVal nSpace As String, _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(elementName, nSpace)
         Return nodeElement
      End Function

      Public Shared Function NewElement( _
                  ByVal nSpace As String, _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String, _
                  ByVal name As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(elementName, nSpace)
         nodeElement.Attributes.Append(xmlHelpers.NewAttribute( _
                  xmlDoc, "Name", name))
         Return nodeElement
      End Function

      Public Shared Function NewElement( _
                  ByVal prefix As String, _
                  ByVal nSpace As String, _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(prefix, elementName, nSpace)
         Return nodeElement
      End Function

      Public Shared Function NewElement( _
                  ByVal prefix As String, _
                  ByVal nSpace As String, _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal elementName As String, _
                  ByVal name As String) _
                  As Xml.XmlElement
         Dim nodeElement As Xml.XmlElement
         nodeElement = xmlDoc.CreateElement(prefix, elementName, nSpace)
         nodeElement.Attributes.Append(xmlHelpers.NewAttribute( _
                  xmlDoc, "Name", name))
         Return nodeElement
      End Function
#End Region

      Public Shared Function NewAttribute( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal name As String, _
                  ByVal value As String) _
                  As Xml.XmlAttribute
         Dim nodeAttribute As Xml.XmlAttribute
         nodeAttribute = xmlDoc.CreateAttribute(name)
         nodeAttribute.Value = value
         Return nodeAttribute
      End Function

      Public Shared Function NewBoolAttribute( _
                  ByVal xmlDoc As Xml.XmlDocument, _
                  ByVal name As String, _
                  ByVal value As Boolean) _
                  As Xml.XmlAttribute
         Dim nodeAttribute As Xml.XmlAttribute
         nodeAttribute = xmlDoc.CreateAttribute(name)
         If value Then
            nodeAttribute.Value = "true"
         Else
            nodeAttribute.Value = "false"
         End If
         Return nodeAttribute
      End Function

      Public Shared Sub AddOrUpdateAttribute( _
                  ByVal node As Xml.XmlNode, _
                  ByVal name As String, _
                  ByVal value As String)
         Dim nodeAttribute As Xml.XmlNode
         Dim xmlDoc As Xml.XmlDocument
         If TypeOf node Is Xml.XmlDocument Then
            xmlDoc = CType(node, Xml.XmlDocument)
         Else
            xmlDoc = node.OwnerDocument
         End If
         If Not node.Attributes Is Nothing Then
            nodeAttribute = node.Attributes.GetNamedItem(name)
            If nodeAttribute Is Nothing Then
               node.Attributes.Append(NewAttribute(xmlDoc, name, value))
            Else
               nodeAttribute.Value = value
            End If
         End If
      End Sub

      Public Shared Sub AppendParts( _
                  ByVal xmlOut As Xml.XmlDocument, _
                  ByVal node As Xml.XmlNode, _
                  ByVal name As String, _
                  ByVal partString As String)
         Dim parts() As String

         parts = partString.Split(","c)
         For Each s As String In parts
            node.AppendChild(xmlHelpers.NewElement(xmlOut, name, s))
         Next
      End Sub

      Public Shared Sub AppendIfExists(ByVal node As Xml.XmlNode, ByVal nodeChild As Xml.XmlNode)
         If Not nodeChild Is Nothing Then
            node.AppendChild(nodeChild)
         End If
      End Sub

      Public Shared Function GetSchemaForNode( _
                     ByVal nodeName As String, _
                     ByVal xsdDoc As Xml.XmlDocument) _
                     As Xml.XmlNode
         If Not xsdDoc Is Nothing Then
            Return xsdDoc.SelectSingleNode("//xs:element[@name='" & nodeName & "']", _
                           GetXSDNamespaceManager)
         End If
         Return Nothing
      End Function

      'Public Shared Function LoadFile( _
      '         ByVal xmlFileName As String, _
      '         ByVal xsdDoc As Xml.XmlDocument) _
      '         As Xml.XmlDocument
      '   Dim xmlDoc As New Xml.XmlDocument
      '   Dim textReader As Xml.XmlTextReader = Nothing
      '   Dim validReader As Xml.XmlValidatingReader
      '   xsdDoc = Nothing
      '   Try
      '      xmlFileName = xmlFileName
      '      textReader = New Xml.XmlTextReader(xmlFileName)
      '      validReader = New Xml.XmlValidatingReader(textReader)
      '      validReader.ValidationType = Xml.ValidationType.Schema
      '      xmlDoc.Load(validReader)
      '   Finally
      '      If textReader IsNot Nothing Then
      '         textReader.Close()
      '      End If
      '   End Try
      '   Return xmlDoc
      'End Function

      Public Shared Sub ClearNodes( _
               ByVal nodeRoot As Xml.XmlNode, _
               ByVal xpath As String, _
               ByVal nsMgr As Xml.XmlNamespaceManager)
         Dim nodeList As Xml.XmlNodeList
         nodeList = nodeRoot.SelectNodes(xpath, nsMgr)
         For Each node As Xml.XmlNode In nodeList
            nodeRoot.RemoveChild(node)
         Next
      End Sub

      Public Shared Function GetLocalPart(ByVal s As String) As String
         Return s.Substring(s.IndexOf(":") + 1)
      End Function

      Public Shared Function MakeNewDocFromXSDDoc( _
               ByVal xsdDoc As Xml.XmlDocument) _
               As Xml.XmlDocument
         Dim xmlDoc As Xml.XmlDocument
         Dim node As Xml.XmlNode
         Dim nodeList As Xml.XmlNodeList
         Dim nsmgr As Xml.XmlNamespaceManager
         Dim targetNamespace As String
         Dim prefix As String
         Dim newNode As Xml.XmlNode
         xmlDoc = New Xml.XmlDocument
         nsmgr = BuildNamespacesManagerForDoc(xsdDoc)
         targetNamespace = GetTargetNamespace(xsdDoc, nsmgr)
         prefix = GetPrefix(xsdDoc, nsmgr, targetNamespace)
         xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", String.Empty, "yes"))
         node = xsdDoc.SelectSingleNode("/xs:schema/xs:element[@kd:Auto='true']", nsmgr)
         If Not node Is Nothing Then
            newNode = xmlDoc.AppendChild(MakeNewNodeFromXSDNode(xmlDoc, targetNamespace, prefix, node, nsmgr))
            ' For now, I'm just supporting the one level I need
            nodeList = node.SelectNodes(".//xs:element[@kd:Auto='true']", nsmgr)
            For Each childNode As Xml.XmlNode In nodeList
               newNode.AppendChild(MakeNewNodeFromXSDNode(xmlDoc, targetNamespace, prefix, node, nsmgr))
            Next
         End If
         Return xmlDoc
      End Function

      Public Shared Function GetTargetNamespace( _
               ByVal xsdDoc As Xml.XmlDocument, _
               ByVal nsmgr As Xml.XmlNamespaceManager) As String
         Dim node As Xml.XmlNode
         node = xsdDoc.SelectSingleNode("xs:schema", nsmgr)
         If Not node Is Nothing Then
            Return Tools.GetAttributeOrEmpty(node, "targetNamespace")
         End If
         Return Nothing
      End Function

      Public Shared Function GetPrefix( _
               ByVal doc As Xml.XmlDocument, _
               ByVal nsmgr As Xml.XmlNamespaceManager, _
               ByVal nSpace As String) _
               As String
         Dim ret As String
         Dim node As Xml.XmlNode
         ret = nsmgr.LookupPrefix(nSpace)
         If ret Is Nothing Then
            node = GetRootNode(doc)
            If Not node Is Nothing Then
               ret = Tools.GetAttributeOrEmpty(node, "kd:Prefix")
            End If
         End If
         Return ret
      End Function

      Public Shared Function MakeNewNodeFromXSDNode( _
               ByVal xmldoc As Xml.XmlDocument, _
               ByVal namespaceURI As String, _
               ByVal prefix As String, _
               ByVal xsdElementNode As Xml.XmlNode, _
               ByVal xsdNsMgr As Xml.XmlNamespaceManager) _
               As Xml.XmlNode
         Return MakeNewNodeFromXSDNode(xmldoc, _
                  Utility.Tools.GetAttributeOrEmpty(xsdElementNode, "name"), _
                  namespaceURI, prefix, xsdElementNode, xsdNsMgr)
      End Function

      Public Shared Function MakeNewNodeFromXSDNode( _
               ByVal xmldoc As Xml.XmlDocument, _
               ByVal name As String, _
               ByVal namespaceURI As String, _
               ByVal prefix As String, _
               ByVal xsdElementNode As Xml.XmlNode, _
               ByVal xsdNsMgr As Xml.XmlNamespaceManager) _
               As Xml.XmlNode
         Dim attrName As String
         Dim dataNode As Xml.XmlElement = xmldoc.CreateElement( _
                              prefix & ":" & name, namespaceURI)
         Dim xsdAttrNodeList As Xml.XmlNodeList
         Dim attrValue As String
         Dim xsdNodeList As Xml.XmlNodeList
         Dim xsdTypeNode As Xml.XmlNode
         Dim xsdAttrTypeNode As Xml.XmlNode
         Dim typeName As String = Utility.Tools.GetAttributeOrEmpty( _
                              xsdElementNode, "type")
         If xsdElementNode.Attributes.GetNamedItem("type") Is Nothing Then
            ' This is an anonymous type
            xsdTypeNode = xsdElementNode.SelectSingleNode("descendant-or-self::xs:complexType", xsdNsMgr)
         Else
            ' This is a named type
            ' The following is an XPath union
            xsdTypeNode = xsdElementNode.SelectSingleNode( _
                              "/xs:schema/xs:complexType[@name='" & typeName & "']", _
                              xsdNsMgr)
         End If

         If Not xsdTypeNode Is Nothing Then
            xsdAttrNodeList = xsdTypeNode.SelectNodes("xs:attribute", xsdNsMgr)
            For Each xsdAttrNode As Xml.XmlNode In xsdAttrNodeList
               attrName = Utility.Tools.GetAttributeOrEmpty(xsdAttrNode, "name")
               typeName = Utility.Tools.GetAttributeOrEmpty(xsdAttrNode, "type")
               ' Cheat on namespace handling
               attrValue = ""
               If typeName.StartsWith("xs:") Then
                  Select Case typeName
                     Case "xs:int"
                        attrValue = "0"
                     Case "xs:boolean"
                        attrValue = "false"
                  End Select
               Else
                  ' A simple type, assume its a simple type of enumeratio, grab first
                  xsdAttrTypeNode = xsdElementNode.SelectSingleNode( _
                              "/xs:schema/xs:simpleType[@name='" & typeName & _
                              "']/xs:restriction/xs:enumeration", xsdNsMgr)
                  If Not xsdAttrTypeNode Is Nothing Then
                     attrValue = Tools.GetAttributeOrEmpty(xsdAttrTypeNode, "value")
                  End If
               End If
               dataNode.Attributes.Append(Utility.xmlHelpers.NewAttribute( _
                              xmldoc, attrName, attrValue))
            Next
            ' CHANGE 20041121: Changed this
            xsdNodeList = xsdTypeNode.SelectNodes( _
                               ".//xs:element[@kd:Auto='true']", xsdNsMgr)
            'xsdNodeList = xsdTypeNode.SelectNodes( _
            '                  "xs:sequence/xs:element|xs:all/xs:element", nsmgr)
            ' I'm not currently supporting choice because I am not sure what you'd do
            For Each xsdChildNode As Xml.XmlNode In xsdNodeList
               dataNode.AppendChild(MakeNewNodeFromXSDNode( _
                              xmldoc, namespaceURI, prefix, xsdChildNode, xsdNsMgr))
            Next
         End If
         Return dataNode
      End Function
#End Region

      '#Region "Protected and Friend Methods and Properties"
      '#End Region

#Region "Private Methods and Properties - empty"
#End Region

#Region "File Support - moved to accomodate command line"
      Public Shared Function OpenXML(ByVal filename As String) As Xml.XmlDocument
         Dim ret As Xml.XmlDocument
         ret = New Xml.XmlDocument
         ret.Load(filename)
         Return ret
      End Function

      Public Shared Function OpenXsdAsXml( _
                     ByVal xmlDoc As Xml.XmlDocument, _
                     ByVal xFilepath As String, _
                     ByVal basePath As String, _
                     ByVal path As String) _
                     As Xml.XmlDocument
         ' CHANGED: KAD 20041026 Changes made to the following method 
         Dim xsdFileName As String
         Dim xfileFullPath As String
         Dim retXSD As Xml.XmlDocument = Nothing
         Dim rootNode As Xml.XmlNode
         rootNode = GetRootNode(xmlDoc)
         If xmlDoc.ChildNodes.Count > 1 Then
            xsdFileName = GetXSDFileNameFromSchemaLocation(xmlDoc)
            If Not xsdFileName Is Nothing Then
               If IO.File.Exists(xsdFileName) Then
                  retXSD = Utility.xmlHelpers.OpenXML(xsdFileName)
               Else
                  xfileFullPath = Utility.Tools.FixPath(xFilepath, _
                        basePath, Nothing, Nothing)
                  xsdFileName = IO.Path.Combine(xfileFullPath, _
                        IO.Path.GetFileName(xsdFileName))
                  If IO.File.Exists(xsdFileName) Then
                     retXSD = Utility.xmlHelpers.OpenXML(xsdFileName)
                  End If
               End If
            End If
            Return retXSD
         End If

         Return Nothing
      End Function

      'Public Shared Function LoadAndValidate( _
      '              ByVal xmlFileName As String, _
      '              ByVal xmlSchema As Xml.schema.XmlSchema) _
      '              As Xml.XmlDocument
      '   Dim stream As New IO.FileStream(xmlFileName, IO.FileMode.Open)
      '   Return LoadAndValidate(stream, xmlSchema)
      'End Function

      'Public Shared Function LoadAndValidate( _
      '              ByVal stream As IO.Stream, _
      '              ByVal xmlSchema As Xml.schema.XmlSchema) _
      '              As Xml.XmlDocument
      '   Dim xmlDoc As New Xml.XmlDocument
      '   Dim textReader As Xml.XmlTextReader
      '   Dim validReader As Xml.XmlValidatingReader
      '   Try
      '      stream.Position = 0
      '      textReader = New Xml.XmlTextReader(stream)
      '      validReader = New Xml.XmlValidatingReader(textReader)
      '      validReader.Schemas.Add(xmlSchema)
      '      validReader.ValidationType = Xml.ValidationType.Schema
      '      Try
      '         xmlDoc.Load(validReader)
      '      Catch ex As System.Exception
      '         Throw New System.Exception("Could not validate XML file" & _
      '                        vbcrlf & vbcrlf & "More Information: " & _
      '                        vbcrlf & vbcrlf & ex.message)
      '      End Try
      '   Catch ex As System.Exception
      '      Throw
      '   Finally
      '      textReader.Close()
      '   End Try
      '   Return xmlDoc
      'End Function

      Public Shared Function MakeXSLTFriendly(ByVal s As String) As String
         Dim ret As String
         ret = s.Replace("&", "&amp;")
         ret = s.Replace("<", "&lt;")
         Return ret
      End Function

      Public Shared Function GetRootNode( _
               ByVal xmlDoc As Xml.XmlDocument) _
               As Xml.XmlNode
         For Each node As Xml.XmlNode In xmlDoc.ChildNodes
            If node.NodeType = Xml.XmlNodeType.Element Then
               Return node
            End If
         Next
         Return Nothing
      End Function

      Public Shared Function GetFirstElementChildNode( _
               ByVal node As Xml.XmlNode) _
               As Xml.XmlNode
         If Not node Is Nothing Then
            For Each childNode As Xml.XmlNode In node.ChildNodes
               If childNode.NodeType = Xml.XmlNodeType.Element Then
                  Return childNode
               End If
            Next
         End If
         Return Nothing
      End Function

      Public Shared Function GetVersion( _
               ByVal xmldoc As Xml.XmlDocument) _
               As String
         Dim node As Xml.XmlNode
         node = xmldoc.SelectSingleNode("//*[local-name()='Version']")
         Return Tools.GetAttributeOrEmpty(node, "Number")
      End Function

      Public Shared Function GetXSDFileNameFromSchemaLocation( _
              ByVal stream As IO.Stream) _
              As String
         Dim xmldoc As New Xml.XmlDocument
         xmldoc.Load(stream)
         Return GetXSDFileNameFromSchemaLocation(xmldoc)
      End Function

      Public Shared Function GetXSDFileNameFromSchemaLocation( _
               ByVal xmlDoc As Xml.XmlDocument) _
               As String
         Dim rootNode As Xml.XmlNode
         rootNode = GetRootNode(xmlDoc)
         If Not rootNode.Attributes.GetNamedItem("schemaLocation", xsiNamespaceURI) _
                                   Is Nothing Then
            Dim temp() As String
            temp = rootNode.Attributes.GetNamedItem("schemaLocation", _
                        xsiNamespaceURI). _
                              Value.Split(" "c)
            Return temp(1)
         End If
         Return Nothing
      End Function


      Public Shared Function GetSchema(ByVal xsdStream As IO.Stream) As Xml.Schema.XmlSchema
         xsdStream.Position = 0
         Return Xml.Schema.XmlSchema.Read(xsdStream, AddressOf XSDFailure)
      End Function

      Private Shared Sub XSDFailure( _
                  ByVal sender As Object, _
                  ByVal args As Xml.Schema.ValidationEventArgs)
         ' KAD: Log args.Message
         Diagnostics.Debug.WriteLine(args.Message)
      End Sub


      'Public Shared Function LoadAndValidateFile( _
      '                 ByVal xmlFileName As String) _
      '                 As Xml.XmlDocument
      '   Dim xmlDoc As New Xml.XmlDocument
      '   Dim textReader As Xml.XmlTextReader
      '   Dim validReader As Xml.XmlValidatingReader
      '   Try
      '      textReader = New Xml.XmlTextReader(xmlFileName)
      '      validReader = New Xml.XmlValidatingReader(textReader)
      '      validReader.ValidationType = Xml.ValidationType.Schema
      '      Try
      '         xmlDoc.Load(validReader)
      '      Catch ex As System.Exception
      '         Throw New System.Exception("Could not validate Harness XML file" & _
      '                        vbcrlf & vbcrlf & "More Information: " & _
      '                        vbcrlf & vbcrlf & ex.message)
      '      End Try
      '   Catch ex As System.Exception
      '      Throw
      '   Finally
      '      textReader.Close()
      '   End Try
      '   Return xmlDoc
      'End Function
#End Region

#Region "Copies of files to facilitate transfer to new version"
      Public Shared Function GetAttributeOrEmptyString( _
            ByVal node As Xml.XmlNode, _
            ByVal ElementName As String, _
            ByVal attributeName As String, _
            ByVal nsmgr As Xml.XmlNamespaceManager) _
            As String
         Dim elem As Xml.XmlNode
         If ElementName Is Nothing OrElse ElementName.Trim.Length = 0 Then
            Return GetAttributeOrEmptyString(node, attributeName)
         Else
            elem = node.SelectSingleNode(ElementName, nsmgr)
            If elem Is Nothing Then
               Return ""
            Else
               Return GetAttributeOrEmptyString(elem, attributeName)
            End If
         End If
      End Function

      Public Shared Function GetAttributeOrEmptyString( _
                     ByVal node As Xml.XmlNode, _
                     ByVal attributeName As String) _
                     As String
         Dim ret As String = ""
         If Not node Is Nothing Then
            If Not node.Attributes Is Nothing Then
               Dim attr As Xml.XmlNode = node.Attributes.GetNamedItem(attributeName)
               If Not attr Is Nothing Then
                  ret = attr.Value
               End If
            End If
         End If
         Return ret
      End Function

      Public Shared Function GetAttributeBooleanOrFalse( _
                 ByVal node As Xml.XmlNode, _
                 ByVal ElementName As String, _
                 ByVal attributeName As String, _
                 ByVal nsmgr As Xml.XmlNamespaceManager) _
                 As Boolean
         Dim elem As Xml.XmlNode
         If ElementName.Trim.Length = 0 Then
            Return GetAttributeBooleanOrFalse(node, attributeName)
         Else
            elem = node.SelectSingleNode(ElementName, nsmgr)
            If elem Is Nothing Then
               Return False
            Else
               Return GetAttributeBooleanOrFalse(elem, attributeName)
            End If
         End If
      End Function

      Public Shared Function GetAttributeBooleanOrFalse( _
                    ByVal node As Xml.XmlNode, _
                    ByVal attributeName As String) _
                    As Boolean
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If Not ret Is Nothing AndAlso ret.Trim.ToLower = "true" Then
            Return True
         Else
            Return False
         End If
      End Function

      Public Shared Function GetAttributeIntegerOrZero( _
                   ByVal node As Xml.XmlNode, _
                   ByVal attributeName As String) _
                   As Int32
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToInt32(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeByteOrZero( _
                ByVal node As Xml.XmlNode, _
                ByVal attributeName As String) _
                As Byte
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToByte(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeSignedByteOrZero( _
               ByVal node As Xml.XmlNode, _
               ByVal attributeName As String) _
               As SByte
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToSByte(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeUnsignedIntOrZero( _
                 ByVal node As Xml.XmlNode, _
                 ByVal attributeName As String) _
                 As UInt32
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToUInt32(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeUnsignedLongOrZero( _
                ByVal node As Xml.XmlNode, _
                ByVal attributeName As String) _
                As UInt64
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToUInt64(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeLongOrZero( _
                ByVal node As Xml.XmlNode, _
                ByVal attributeName As String) _
                As Int64
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Convert.ToInt64(Microsoft.VisualBasic.Val(ret))
         End If
      End Function

      Public Shared Function GetAttributeFloatOrZero( _
                   ByVal node As Xml.XmlNode, _
                   ByVal attributeName As String) _
                   As Double
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return 0
         Else
            Return Microsoft.VisualBasic.Val(ret)
         End If
      End Function

      Public Shared Function GetAttributeDateOrMinDate( _
                   ByVal node As Xml.XmlNode, _
                   ByVal attributeName As String) _
                   As DateTime
         Dim ret As String = GetAttributeOrEmptyString(node, attributeName)
         If ret Is Nothing OrElse ret.Trim.Length = 0 Then
            Return System.DateTime.MinValue
         Else
            If Microsoft.VisualBasic.IsDate(ret) Then
               Return CDate(ret)
            End If
         End If
      End Function

      Public Shared Function GetAttributeEnumOrZero( _
              ByVal node As Xml.XmlNode, _
              ByVal attributeName As String, _
              ByVal enumType As System.Type) _
              As System.Object
         Dim s As String = GetAttributeOrEmptyString(node, attributeName)
         If Not s.Trim.Length = 0 Then
            Return [Enum].Parse(enumType, s)
         End If
         Return Nothing
      End Function
#End Region
   End Class
End Namespace